package simulaco.business;

import gminet.infra.business.BusinessException;
import gminet.infra.business.BusinessObject;
import gminet.infra.db.Transaction;
import gminet.infra.db.TransactionException;
import gminet.infra.toolkit.DateToolkit;
import gminet.infra.toolkit.NumberToolkit;
import gminet.infra.toolkit.StringToolkit;

import java.sql.Connection;
import java.util.Date;
import java.util.List;

import simulaco.dao.ConcursoDAO;
import simulaco.dao.ConcursoFilter;
import simulaco.dao.QuestaoDAO;
import simulaco.dto.Concurso;
import simulaco.dto.Situacao;

public class ConcursoBusiness extends BusinessObject {

    public static Concurso findByPK(int concursoId) throws TransactionException {

        Concurso concurso = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            concurso = ConcursoDAO.findByPK(concursoId, conn);
            if (concurso != null) {
                concurso.setListaMateria(MateriaBusiness.findByConcurso(concursoId, conn));
            }
        } finally {
            transaction.release();
        }
        return concurso;
    }

    public static List<Concurso> findAll() throws TransactionException {

        List<Concurso> concursos = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            concursos = ConcursoDAO.findAll(conn);
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return concursos;
    }

    public static List<Concurso> findByInstituicao(int instituicaoId) throws TransactionException {

        List<Concurso> concursos = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            concursos = findByInstituicao(instituicaoId, conn);
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return concursos;
    }

    protected static List<Concurso> findByInstituicao(int instituicaoId, Connection conn) throws TransactionException {

        List<Concurso> concursos = null;
        ConcursoFilter concursoFilter = new ConcursoFilter();
        concursoFilter.setCodigoInstituicao(instituicaoId);
        concursos = ConcursoDAO.findByFilter(concursoFilter, conn);
        return concursos;
    }

    public static List<Concurso> findByOrgao(int orgaoId) throws TransactionException {

        List<Concurso> concursos = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            concursos = findByOrgao(orgaoId, conn);
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return concursos;
    }

    protected static List<Concurso> findByOrgao(int orgaoId, Connection conn) throws TransactionException {

        List<Concurso> concursos = null;
        ConcursoFilter concursoFilter = new ConcursoFilter();
        concursoFilter.setCodigoOrgao(orgaoId);
        concursos = ConcursoDAO.findByFilter(concursoFilter, conn);
        return concursos;
    }

    public static List<Concurso> findByOrgaoInstituicaoNivel(int orgaoId, int instituicaoId, int nivelId) throws TransactionException {

        List<Concurso> concursos = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            concursos = findByOrgaoInstituicaoNivel(orgaoId, instituicaoId, nivelId, conn);
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return concursos;
    }

    protected static List<Concurso> findByOrgaoInstituicaoNivel(int orgaoId, int instituicaoId, int nivelId, Connection conn) throws TransactionException {

        List<Concurso> concursos = null;
        ConcursoFilter concursoFilter = new ConcursoFilter();
        concursoFilter.setCodigoOrgao(orgaoId);
        concursoFilter.setCodigoInstituicao(instituicaoId);
        concursoFilter.setCodigoNivel(nivelId);
        concursos = ConcursoDAO.findByFilter(concursoFilter, conn);
        return concursos;
    }

    public static Concurso insert(Concurso concurso) throws BusinessException, TransactionException {

        Concurso newConcurso = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            // CONCURSO
            Date dataAtual = DateToolkit.getDate();
            int rangeId = createRangeId(concurso.getIdentificacao());
            concurso.setCodigo(ConcursoDAO.getNextCodigo(conn, rangeId, rangeId + 1000));
            if (concurso.getSituacao().getCodigo() == 0) {
                concurso.setSituacao(Situacao.DESABILITADO);
            }
            concurso.setDataCadastro(dataAtual);
            ConcursoDAO.insert(concurso, conn);
            // CONCURSO MATERIAS
            ConcursoMateriaBusiness.insertAll(concurso, conn);
            // COMMIT
            transaction.commit();
            //
            newConcurso = concurso;
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return newConcurso;
    }

    private static int createRangeId(String concursoName) {

        String strCodigo = "1";
        String caracter1 = concursoName.substring(0, 1).toUpperCase();
        String caracter2 = concursoName.length() > 1 ? concursoName.substring(1, 2).toUpperCase() : "A";
        int valor1 = Math.abs(caracter1.compareTo("A") + 1);
        if (StringToolkit.isDigit(caracter1)) {
            valor1 = 0;
        }
        int valor2 = Math.abs(caracter2.compareTo("A") / 3);
        if (StringToolkit.isDigit(caracter2)) {
            valor2 = 0;
        }
        strCodigo += NumberToolkit.getStringFromInt(Math.min(valor1, 99), 2);
        strCodigo += NumberToolkit.getStringFromInt(Math.min(valor2, 9), 1);
        strCodigo += "000";
        return Integer.parseInt(strCodigo);
    }

    public static void update(Concurso concurso) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            ConcursoDAO.update(concurso, conn);
            ConcursoMateriaBusiness.updateAll(concurso, conn);
            // COMMIT
            transaction.commit();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    public static void updateStatus(Concurso concurso) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            Concurso auxConcurso = ConcursoDAO.findByPK(concurso.getCodigo(), conn);
            auxConcurso.setSituacao(concurso.getSituacao());
            ConcursoDAO.update(auxConcurso, conn);
            // COMMIT
            transaction.commit();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    public static void delete(Concurso concurso) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            // VERIFICA SE TEM QUESTOES VINCULADAS
            if (QuestaoDAO.findByConcurso(concurso.getCodigo(), conn).size() > 0) {
                throw new BusinessException("Não é possivel excluir este concurso. Existem provas vinculadas.");
            } else {
                // EXCLUI CONCURSO MATERIAS
                ConcursoMateriaBusiness.deleteByConcurso(concurso, conn);
                // EXCLUI O CONCURSO
                ConcursoDAO.delete(concurso, conn);
                //
                transaction.commit();
            }
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

}
